home *** CD-ROM | disk | FTP | other *** search
/ 100 Great Games for Palm OS 2 / PalmV2012301.ISO / puzzles / Pilot Mines / src / mine.c < prev    next >
C/C++ Source or Header  |  1999-06-02  |  19KB  |  863 lines

  1. /*
  2.  * PilotMines is Copyright (c) 1997, 1998 by Thomas Pundt
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software for any
  5.  * purpose, without fee, and without a written agreement is hereby granted,
  6.  * provided that the above copyright notice and this paragraph and the
  7.  * following two paragraphs appear in all copies.
  8.  *
  9.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
  10.  * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
  11.  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
  12.  * THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  13.  *
  14.  * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
  15.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  16.  * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
  17.  * BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
  18.  * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  19.  *
  20.  */
  21.  
  22. #include <Common.h>
  23. #include <System/KeyMgr.h>
  24. #include <System/SysAll.h>
  25. #include <UI/UIAll.h>
  26.  
  27. #include "minercp.h"
  28. #include "mine.h"
  29. #include "hscore.h"
  30.  
  31. /*
  32.   bit 5   : Marked
  33.   bit 4   : Cover/uncovered
  34.   bit 3-0 : number of mines in adjoining cells
  35. */
  36. #define MINE    0x09
  37. #define COVERED 0x10
  38. #define MARKED    0x20
  39. #define TMPMARK    0x40
  40.  
  41. #define InArray(x,y)    (((x)>=0 && (x)<WIDTH) && ((y)>=0 && (y)<HEIGHT))
  42. #define IsVisible(x,y)    ((game.minefield[x][y] & COVERED) ? 0 : 1)
  43.  
  44. /*
  45.  * Game options
  46.  */
  47. #define ShowAll          1
  48. #define AlternateControl 2
  49. #define FirstNoMine      4
  50.  
  51. static int levelmines[] = { 10, 30, 50, 70 };
  52.  
  53. static struct { SWord x,y; } stack[WIDTH*HEIGHT];
  54.  
  55. static int numuncovered, marked, nummines, StckPtr;
  56. static Boolean isHighlighted;
  57. static ULong GameStartedAt;
  58. static WinHandle bitmaps;  // Offscreen Window with tile bitmaps
  59.  
  60. long score = 0;
  61.  
  62. static DmOpenRef pmDB;
  63. Game game;
  64.  
  65. /*
  66.  * mapping function, that applies f to all neighbours of (x,y)
  67.  */
  68. static int Neighbours (func f, SWord x, SWord y)
  69. {
  70.   int res = 0;
  71.   res += f(x-1,y-1); res += f(x,y-1); res += f(x+1,y-1);
  72.   res += f(x-1,y  );                  res += f(x+1,y  );
  73.   res += f(x-1,y+1); res += f(x,y+1); res += f(x+1,y+1);
  74.   return res;
  75. }
  76.  
  77. static int IsMine(SWord x, SWord y)
  78. {
  79.   return (InArray(x,y) && (game.minefield[x][y] & 0xf) == MINE);
  80. }
  81.                                                                 
  82. static int IsMarked(SWord x, SWord y)
  83. {
  84.  return (InArray(x,y) && (game.minefield[x][y] & MARKED));
  85. }
  86.  
  87. /*
  88.  * computes the number of mines around field (x,y)
  89.  */
  90. static int countMines(int x, int y)
  91. {
  92.   return Neighbours (IsMine, x, y);
  93. }
  94.  
  95. /*
  96.  * computes the marked fields (supposed mines) around field (x,y)
  97.  */
  98. static int foundMines(int x, int y)
  99. {
  100.   return Neighbours (IsMarked, x, y);
  101. }
  102.  
  103. /*
  104.  * pushes (x,y) on the stack, if field (x,y) isn't marked, isn't 
  105.  * visible, and isn't already on the stack.
  106.  */
  107. static int push(SWord x, SWord y)
  108. {
  109.   if (InArray(x,y) && !(game.minefield[x][y] & (MARKED|TMPMARK)) &&
  110.      (game.minefield[x][y] & COVERED)) {
  111.     game.minefield[x][y] |= TMPMARK;
  112.     stack[StckPtr].x=x;
  113.     stack[StckPtr].y=y;
  114.     StckPtr++;
  115.   }
  116.   return StckPtr;
  117. }
  118.  
  119. /*
  120.  * pops the topmost element (x,y) off the stack, and stores it in
  121.  * the parameters x and y.
  122.  */
  123. static void pop(SWord *x, SWord *y)
  124. {
  125.   StckPtr--;
  126.   *x=stack[StckPtr].x;
  127.   *y=stack[StckPtr].y;
  128. }
  129.  
  130. /*
  131.  * Draw the cell at coordinates (x,y); if Id==0, look at the contents 
  132.  * of field (x,y) and decide what pattern to draw; else draw pattern
  133.  * Id.
  134.  */
  135. static void DrawCell(SWord x, SWord y, int Id)
  136. {
  137.   RectangleType rect;
  138.   Byte field = game.minefield[x][y] & ~TMPMARK;
  139.   
  140.   if (!Id) {
  141.     if (field & MARKED)
  142.       Id = ID_Flag;
  143.     else if (field & COVERED)
  144.       Id = ID_Covered;
  145.     else 
  146.       Id = ID_Blank+field;
  147.   }
  148.  
  149.   // Copy bitmap from offscreen window to active window
  150.   rect.topLeft.x = (Id - ID_Flag)*10;
  151.   rect.topLeft.y = 0;
  152.   rect.extent.x = rect.extent.y = 10;
  153.   WinCopyRectangle(bitmaps,WinGetActiveWindow(),&rect,x*10,(y+2)*10,scrCopy);
  154. }
  155.  
  156. /*
  157.  * Draw the "mines left to mark" status information
  158.  */
  159. static void DrawMarked()
  160. {
  161.    char buf[2];
  162.    buf[0] = (nummines - marked) / 10 + 48;
  163.    buf[1] = (nummines - marked) % 10 + 48;
  164.    WinDrawInvertedChars(buf, 2, 10, 0);
  165. }
  166.  
  167. /*
  168.  * Draw the "passed time" status information; if a menubar is active,
  169.  * don't draw.
  170.  */
  171. static void DrawTime()
  172. {
  173.   char buf[5] = "00:00";
  174.   ULong actseconds;
  175.   MenuBarPtr menu;
  176.  
  177.   if ((menu = MenuGetActiveMenu()) && menu->attr.visible)
  178.     return;
  179.  
  180.   actseconds = TimGetSeconds() - GameStartedAt;
  181.   if (actseconds>3599)
  182.     actseconds = 3599;
  183.   buf[4] = actseconds % 10 + 48;
  184.   buf[3] = (actseconds / 10) % 6 + 48;
  185.   buf[1] = (actseconds / 60) % 10 + 48;
  186.   buf[0] = (actseconds / 600) % 10 + 48;
  187.   WinDrawInvertedChars(buf, 5, 130, 0);
  188. }
  189.  
  190. /*
  191.  * Draw the field with all elements uncovered.
  192.  */
  193. static void UncoverAll()
  194. {
  195.   SWord x,y;
  196.  
  197.   if (!(game.options & ShowAll))
  198.     return;
  199.   
  200.   for (y=0; y<HEIGHT; y++)
  201.     for (x=0; x<WIDTH; x++)
  202.       if (!IsVisible(x,y)) {
  203.         game.minefield[x][y] &= 0xf;
  204.         DrawCell(x,y,0);
  205.       }
  206. }
  207.  
  208. /*
  209.  * Draw the field; is called, if status was restored after an application
  210.  * switch.
  211.  */
  212. static void ShowFormMine()
  213. {
  214.   SWord x,y;
  215.  
  216.   FrmDrawForm(FrmGetActiveForm());
  217.   for (y=0; y<HEIGHT; y++)
  218.     for (x=0; x<WIDTH; x++)
  219.       DrawCell(x,y,0);
  220.   GameStartedAt = TimGetSeconds() - game.seconds;
  221.   DrawMarked();
  222. }
  223.  
  224. /*
  225.  * show the contents of field (x,y); "recursively" (well a recursive
  226.  * function actually would crash the application :-) uncover all 
  227.  * neighbours of a field, if it has no mine as neighbour.
  228.  */
  229. static int Show(SWord x, SWord y)
  230. {
  231.   push(x,y);
  232.   while(StckPtr) {  
  233.     pop(&x,&y);
  234.     game.minefield[x][y] &= ~COVERED;
  235.     numuncovered++;
  236.     DrawCell(x, y, 0);
  237.     if (IsMine(x,y)) {
  238.       if (game.done == IsRunning) 
  239.         game.done = IsLost;
  240.         UncoverAll();
  241.     } else {
  242.       if (game.done == IsRunning && numuncovered + nummines == WIDTH*HEIGHT) {
  243.         game.done = IsWon;
  244.         score = TimGetSeconds() - GameStartedAt;
  245.         if (score>3599) score = 3599;
  246.       }
  247.       if (game.minefield[x][y] == TMPMARK) {
  248.         Neighbours (push, x, y);
  249.       }
  250.     }
  251.   }
  252.   return 0;
  253. }
  254.  
  255. /*
  256.  * highlight covered field (x,y). Is called, if you tap on an uncovered field.
  257.  */
  258. static int Highlight(SWord x, SWord y)
  259. {
  260.   if (InArray(x,y) && !IsMarked(x,y) && !IsVisible(x,y))
  261.     DrawCell(x, y, ID_Gray);
  262.   return 0;
  263. }
  264.  
  265. /*
  266.  * undo any highlighting done on field (x,y)
  267.  */
  268. static int unHighlight(SWord x, SWord y)
  269. {
  270.   if (InArray(x,y) && !IsMarked(x,y) && !IsVisible(x,y))
  271.     DrawCell(x, y, 0);
  272.   return 0;
  273. }
  274.  
  275. /*
  276.  * compute values "numuncovered" and "marked" after restoring 
  277.  * saved status from an application switch.
  278.  */
  279. static void InitBoard()
  280. {
  281.   SWord x, y;
  282.   WinHandle tmpHandle;
  283.   VoidHand bitmapHandle;
  284.   BitmapPtr bitmap;
  285.   Word err;
  286.  
  287.   numuncovered = 0;
  288.   marked = 0;
  289.  
  290.   for (y=0; y<HEIGHT; y++)
  291.     for (x=0; x<WIDTH; x++) {
  292.       if (IsMarked(x,y))
  293.         marked++;
  294.       if (IsVisible(x,y))
  295.         numuncovered++;
  296.   }
  297.  
  298.   bitmaps = WinCreateOffscreenWindow(140, 10, screenFormat, &err);
  299.   tmpHandle = WinSetDrawWindow(bitmaps);
  300.   
  301.   for (x=0; x<14; x++) {
  302.     bitmapHandle = DmGetResource('Tbmp', ID_Flag+x);
  303.     bitmap = MemHandleLock(bitmapHandle);
  304.     WinDrawBitmap(bitmap, x*10, 0);
  305.     MemHandleUnlock(bitmapHandle);
  306.     DmReleaseResource(bitmapHandle);
  307.   } 
  308.  
  309.   WinSetDrawWindow(tmpHandle);
  310. }
  311.  
  312. static void SetupBoard(SWord x, SWord y)
  313. {
  314.   SWord      ix,iy,pieces;
  315.  
  316.   SysRandom(TimGetSeconds());
  317.   for (pieces=0; pieces<nummines; pieces++) {
  318.     do {
  319.       ix = SysRandom(0) % 16;
  320.       iy = SysRandom(0) % 14;
  321.     } while (IsMine(ix,iy) || ((ix == x) && (iy == y)));
  322.     game.minefield[ix][iy] = MINE+COVERED;
  323.   }
  324.  
  325.   for (iy=0; iy<HEIGHT; iy++)
  326.     for (ix=0; ix<WIDTH; ix++)
  327.       if (!IsMine(ix,iy))
  328.         game.minefield[ix][iy] = countMines(ix,iy)+COVERED;
  329. }
  330.  
  331. /*
  332.  * Initialize the game. Compute an initial mine layout an make all
  333.  * necessary drawings.
  334.  */
  335. static void InitFormMine()
  336. {
  337.   SWord      x,y;
  338.  
  339.   FrmDrawForm(FrmGetActiveForm());
  340.  
  341.   for (y=0; y<HEIGHT; y++)
  342.     for (x=0; x<WIDTH; x++) {
  343.       game.minefield[x][y] = COVERED;
  344.       DrawCell(x, y, ID_Covered);
  345.     }
  346.  
  347. // Changed by Lucas Bremgartner
  348.   if ((game.options & FirstNoMine) == false) {
  349.     SetupBoard(255,255);
  350.   }
  351. // Changed by Lucas Bremgartner (End)
  352.  
  353.   numuncovered = marked = StckPtr = score = 0;
  354.   game.done = IsToBeStarted;
  355.   isHighlighted = false;
  356.   DrawMarked();
  357. }
  358.  
  359. /*
  360.  * Handle any action necessary, if you tap on field (x,y); 
  361.  * "ctrl == true" means, you've also pressed the PageUp or PageDown button;
  362.  * in that case, a covered unmarked field is marked or a covered marked
  363.  * field is unmarked. Else, a covered field is uncovered.
  364.  */
  365. static Boolean HandlePenDownEvent(SWord x, SWord y, Boolean ctrl)
  366. {
  367.   if (!InArray(x,y))
  368.     return false;
  369.  
  370.   if (game.done == IsToBeStarted) {
  371.     // Insert by Lucas Bremgartner
  372.     if (game.options & FirstNoMine) {
  373.       SetupBoard(x,y);
  374.     }
  375.     // Insert by Lucas Bremgartner (End)
  376.     game.done = IsRunning;
  377.     GameStartedAt = TimGetSeconds();
  378.   }
  379.  
  380.   switch (ctrl) {
  381.   case false:
  382.     if (IsVisible(x,y)) {
  383.       if (foundMines(x,y) == (game.minefield[x][y] & 0xf)) {
  384.         Neighbours (Show, x, y);
  385.       } else {
  386.         Neighbours (Highlight, x, y);
  387.         isHighlighted = true;
  388.       }
  389.     } else {
  390.       if (game.options & AlternateControl) { // "Dylan style controls"
  391.         if (!(game.minefield[x][y] & MARKED)) {
  392.           game.minefield[x][y] |= MARKED;
  393.           DrawCell(x, y, 0);
  394.           marked++;
  395.         } else {
  396.           game.minefield[x][y] &= ~MARKED;
  397.           marked--;
  398.           Show(x,y);
  399.         }
  400.         DrawMarked();
  401.       } else {
  402.         if (!(game.minefield[x][y] & MARKED)) {
  403.           Show(x,y);
  404.         }
  405.       }
  406.     }
  407.     break;
  408.   case true:
  409.     if (!IsVisible(x,y)) {
  410.       if (!(game.minefield[x][y] & MARKED)) {
  411.         game.minefield[x][y] |= MARKED;
  412.         DrawCell(x, y, 0);
  413.         marked++;
  414.       } else {
  415.         game.minefield[x][y] &= ~MARKED;
  416.         DrawCell(x, y, 0);
  417.         marked--;
  418.       }
  419.       DrawMarked();
  420.     }
  421.     break;
  422.   }
  423.  
  424.   return true;
  425. }
  426.  
  427. /*
  428.  * Dispatch any menu events we have to handle
  429.  */
  430. static Boolean MyHandleMenuEvent(EventPtr e)
  431. {
  432.   Boolean handled;
  433.   
  434.   CALLBACK_PROLOGUE
  435.   handled = false;
  436.   
  437.   MenuEraseStatus (MenuGetActiveMenu());
  438.   switch(e->data.menu.itemID) {
  439.  
  440.   case ID_MenuItem: /* New Game */
  441.     InitFormMine();
  442.     handled = true;
  443.     break;
  444.     
  445.   case ID_MenuItem+10: /* About Pilot Mines */
  446.     FrmPopupForm(ID_FrmAbout);
  447.     handled = true; 
  448.     break;
  449.  
  450.   case ID_MenuItem+11: /* Preferences */
  451.     FrmPopupForm(ID_FrmPreferences);
  452.     handled = true; 
  453.     break;
  454.  
  455.   case ID_MenuItem+12: /* High Scores */
  456.     FrmPopupForm(ID_FrmHighScores);
  457.     handled = true; 
  458.     break;
  459.  
  460.   default:
  461.     break;
  462.   }
  463.  
  464.   CALLBACK_EPILOGUE
  465.   return handled;
  466. }
  467.  
  468. /*
  469.  * dispatch all events we have to handle in the main form (the one
  470.  * showing the mine field)
  471.  */
  472. static Boolean MineFormHandleEvent(EventPtr e)
  473. {
  474.   Boolean handled;
  475.   static SWord saveX, saveY;
  476.   
  477.   CALLBACK_PROLOGUE
  478.   handled = false;
  479.  
  480.   if (game.done == Restart)
  481.     InitFormMine();
  482.  
  483.   if (game.done == IsRunning) 
  484.     DrawTime();
  485.  
  486. // Insert by Lucas Bremgarter
  487.   if (game.done == HighScoreWon) {
  488.     if (!FrmAlert(GameOver)) {
  489.       InitFormMine();
  490.     } else {
  491.       game.done = IsFinishedWon;
  492.     }
  493.   }
  494.  
  495.   if (game.done == HighScoreLost) {
  496.     if (!FrmAlert(GameOver+1)) {
  497.       InitFormMine();
  498.     } else {
  499.       game.done = IsFinishedLost;
  500.     }
  501.   }
  502.  
  503. // Insert by Lucas Bremgartner (End)
  504.  
  505.   switch (e->eType) {
  506.  
  507.   case menuEvent:
  508.     handled = MyHandleMenuEvent(e);
  509.     break;
  510.  
  511.   case frmOpenEvent:
  512.     handled = true;
  513.     break;
  514.  
  515.   case keyDownEvent:
  516.     switch(e->data.keyDown.chr) {
  517.     case 'n':
  518.       InitFormMine();
  519.       handled = true;
  520.       break;
  521.  
  522.     case 'h':
  523.       FrmPopupForm(ID_FrmHighScores);
  524.       handled = true;
  525.       break;
  526.  
  527. #ifdef ENGLISH
  528.     case 'p':
  529. #else
  530.     case 'e':
  531. #endif
  532.       FrmPopupForm(ID_FrmPreferences);
  533.       handled = true;
  534.       break;
  535.     }
  536.     break;
  537.  
  538.   case penDownEvent:
  539.     saveX=e->screenX/10;
  540.     saveY=e->screenY/10-2;
  541.     handled = HandlePenDownEvent(saveX, saveY, 
  542.               (KeyCurrentState() & (keyBitPageUp | keyBitPageDown))!=0);
  543.  
  544.     switch (game.done) {
  545.     case IsWon:
  546.       game.done = IsFinishedWon;
  547.       if (isHighScore((int)score))
  548.         FrmPopupForm(ID_FrmHighScores);
  549.       else
  550.         if (!FrmAlert(GameOver))
  551.           InitFormMine();
  552.       break;
  553.     case IsLost:
  554.       game.done = IsFinishedLost;
  555.       if (!FrmAlert(GameOver+1))
  556.         InitFormMine();
  557.       break;
  558.     }
  559.  
  560.     break;
  561.  
  562.   case penUpEvent:
  563.     if (isHighlighted) {
  564.       Neighbours (unHighlight, saveX, saveY);
  565.       isHighlighted = false;
  566.     }
  567.     handled = true;
  568.     break;
  569.  
  570.   default:
  571.     break;
  572.   }  
  573.  
  574.   CALLBACK_EPILOGUE
  575.   return handled;
  576. }
  577.  
  578. /**
  579.  * About Form
  580.  */
  581. static Boolean AboutFormHandleEvent(EventPtr e)
  582. {
  583.   Boolean handled;
  584.   
  585.   CALLBACK_PROLOGUE
  586.   handled = false;
  587.  
  588.   switch (e->eType) {
  589.  
  590.   case frmOpenEvent:
  591.     FrmDrawForm(FrmGetActiveForm());
  592.     handled = true; 
  593.     break;
  594.  
  595.   case ctlSelectEvent:
  596.     if (e->data.ctlSelect.controlID == ID_FrmAboutButton) {
  597.       FrmReturnToForm(0);
  598.       handled = true; 
  599.       break;
  600.     }
  601.     break;
  602.  
  603.   default:
  604.     break;
  605.   }
  606.  
  607.   CALLBACK_EPILOGUE
  608.   return handled;
  609. }
  610.  
  611. /**
  612.  * Preferences Form
  613.  */
  614.  
  615. /*
  616.  * preset the radio buttons for selecting the difficulty level and
  617.  * the check box, that controls if all fields are uncovered, if you
  618.  * loose a game
  619.  */
  620. static void InitFormPref()
  621. {
  622.   FormPtr frm = FrmGetActiveForm();
  623.   FrmSetControlGroupSelection(frm, 1, ID_PrefButton + game.level);
  624.   FrmSetControlValue(frm, FrmGetObjectIndex(frm, ID_PrefButton + 6), 
  625.                      (game.options & ShowAll));
  626.   FrmSetControlValue(frm, FrmGetObjectIndex(frm, ID_PrefButton + 7),
  627.                      (game.options & AlternateControl));
  628. // Insert by Lucas Bremgartner
  629.   FrmSetControlValue(frm, FrmGetObjectIndex(frm, ID_PrefButton + 8),
  630.                      (game.options & FirstNoMine));
  631. // Insert by Lucas Bremgartner (End)
  632.  
  633. }
  634.  
  635. /*
  636.  * handle any events in the preferences form; i.e. setting game
  637.  * difficulty level and "Uncover all" check box.
  638.  */
  639. static Boolean PrefFormHandleEvent(EventPtr e)
  640. {
  641.   Boolean handled;
  642.   
  643.   CALLBACK_PROLOGUE
  644.   handled = false;
  645.  
  646.   switch (e->eType) {
  647.  
  648.   case frmOpenEvent:
  649.     FrmDrawForm(FrmGetActiveForm());
  650.     handled = true; 
  651.     break;
  652.  
  653.   case ctlSelectEvent:
  654.     switch (e->data.ctlSelect.controlID) {
  655.  
  656.     // look at status of radio buttons and save level information accordingly
  657.     case ID_PrefButton + 4: /* Ok */
  658.       game.level = FrmGetObjectId(FrmGetActiveForm(),
  659.                      FrmGetControlGroupSelection(FrmGetActiveForm(), 1)) 
  660.                      - ID_PrefButton;
  661.       nummines = levelmines[game.level];
  662.       FrmReturnToForm(0);
  663.       game.done = Restart;
  664.       handled = true; 
  665.       break;
  666.  
  667.     // don't do anything, simply return to main form
  668.     case ID_PrefButton + 5: /* Cancel */
  669.       FrmReturnToForm(0);
  670.       handled = true; 
  671.       break;
  672.  
  673.     // toggle "uncover all" status information
  674.     case ID_PrefButton + 6: /* Show all */
  675.       game.options ^= ShowAll;
  676.       handled = true;
  677.       break;
  678.  
  679.     // select alternate "Dylan style controls"
  680.     case ID_PrefButton + 7: 
  681.       game.options ^= AlternateControl;
  682.       handled = true;
  683.       break;
  684.  
  685. // Insert by Lucas Bremgartner
  686.     // select alternate "First field is never a mine"
  687.     case ID_PrefButton + 8:
  688.       game.options ^= FirstNoMine;
  689.       handled = true;
  690.       break;
  691. // Insert by Lucas Bremgartner (End)
  692.  
  693.     }
  694.  
  695.     break;
  696.  
  697.   default:
  698.     break;
  699.   }
  700.  
  701.   CALLBACK_EPILOGUE
  702.   return handled;
  703. }
  704.  
  705.  
  706. /**
  707.  * dispatch all previously unhandled events, and set event handling 
  708.  * routines for the different forms
  709.  */
  710. static Boolean ApplicationHandleEvent(EventPtr e)
  711. {
  712.   Boolean handled;
  713.  
  714.   CALLBACK_PROLOGUE
  715.   handled = false;
  716.  
  717.   if (e->eType == frmLoadEvent) {
  718.     Word frmId = e->data.frmLoad.formID;
  719.     FormPtr frm = FrmInitForm(frmId);
  720.     
  721.     FrmSetActiveForm(frm);
  722.     
  723.     switch (frmId) {
  724.     case ID_FrmMine:
  725.       if (game.done == Restart)
  726.         InitFormMine();
  727.       else
  728.         ShowFormMine();
  729.       FrmSetEventHandler(frm, MineFormHandleEvent);
  730.       handled = true;
  731.       break;
  732.  
  733.     case ID_FrmAbout:
  734.       FrmSetEventHandler(frm, AboutFormHandleEvent);
  735.       handled = true;
  736.       break;
  737.  
  738.     case ID_FrmPreferences:
  739.       InitFormPref();
  740.       FrmSetEventHandler(frm, PrefFormHandleEvent);
  741.       handled = true;
  742.       break;
  743.  
  744.     case ID_FrmHighScores:
  745.       FrmSetEventHandler(frm, HighscoresFormHandleEvent);
  746.       handled = true;
  747.       break;
  748.     }
  749.  
  750.   }
  751.  
  752.   CALLBACK_EPILOGUE
  753.   return handled;
  754. }
  755.  
  756.  
  757. /**
  758.  * Database (here: game status information) handling routines.
  759.  */
  760. static Err OpenDatabase(void)
  761. {
  762.   UInt          index = 0;
  763.   VoidHand      RecHandle;
  764.   VoidPtr       RecPointer;
  765.   Err           err;
  766.  
  767.   // Create database, if it doesn't exist, and save default game status.
  768.   if (!(pmDB = DmOpenDatabaseByTypeCreator('Data', 'tpPM', dmModeReadWrite))) {
  769.     if ((err = DmCreateDatabase(0, "PilotMinesDB", 'tpPM', 'Data', false)))
  770.       return err;
  771.     pmDB = DmOpenDatabaseByTypeCreator('Data', 'tpPM', dmModeReadWrite);
  772.  
  773.     RecHandle = DmNewRecord(pmDB, &index, sizeof(game));
  774.     DmWrite(MemHandleLock(RecHandle), 0, &game, sizeof(game));
  775.     MemHandleUnlock(RecHandle);
  776.     DmReleaseRecord(pmDB, index, true);
  777.   }
  778.  
  779.   // Load a saved game status.
  780.   RecHandle = DmGetRecord(pmDB, 0);
  781.   RecPointer = MemHandleLock(RecHandle);
  782.   MemMove(&game, RecPointer, sizeof(game));
  783.   MemHandleUnlock(RecHandle);
  784.   DmReleaseRecord(pmDB, 0, true);
  785.  
  786.   return 0;
  787. }
  788.  
  789. /*
  790.  * Save game status information.
  791.  */
  792. static void SaveStatus()
  793. {
  794.   VoidPtr p = MemHandleLock(DmGetRecord(pmDB, 0));
  795.   game.seconds = TimGetSeconds() - GameStartedAt;
  796.   DmWrite(p, 0, &game, sizeof(game));
  797.   MemPtrUnlock(p);
  798.   DmReleaseRecord(pmDB, 0, true);
  799. }
  800.  
  801. /*
  802.  * Main program.
  803.  */
  804. DWord PilotMain(Word cmd, Ptr cmdPBP, Word launchFlags)
  805. {
  806.   if (cmd==sysAppLaunchCmdNormalLaunch) {
  807.     EventType e;
  808.     short err;
  809.  
  810.     // initialize game status information
  811.     game.level = 2;
  812.     game.version = 1;
  813. // Changed by Lucas Bremgartner
  814.     game.options = ShowAll | FirstNoMine;
  815. // Changed by Lucas Bremgartner (End)
  816.     game.done = Restart;
  817.     game.seconds = 0;
  818.     InitHighScore();
  819.  
  820.     // load a saved game
  821.     if ((err = OpenDatabase()))
  822.       return err;
  823.  
  824.     // restore game status from loaded game, if necessary
  825.     nummines = levelmines[game.level];
  826.     InitBoard();
  827.  
  828.     FrmGotoForm(ID_FrmMine);
  829.  
  830.     do {
  831.       EvtGetEvent(&e,50);
  832.  
  833.       // don't make noise when pressing PgUp/PgDn
  834.       if (e.eType == keyDownEvent && 
  835.          (e.data.keyDown.modifiers & commandKeyMask) &&
  836.          (e.data.keyDown.chr == pageUpChr || e.data.keyDown.chr == pageDownChr))
  837.          continue;
  838.  
  839.       if (SysHandleEvent(&e)) {
  840.         continue;
  841.       }
  842.  
  843.       if (MenuHandleEvent(NULL, &e, &err)) {
  844.         continue;
  845.       }
  846.   
  847.       if (ApplicationHandleEvent(&e)) {
  848.         continue;
  849.       }
  850.  
  851.       FrmDispatchEvent( &e );
  852.       
  853.     } while (e.eType != appStopEvent);
  854.  
  855.     FrmCloseAllForms();
  856.     SaveStatus();
  857.     DmCloseDatabase(pmDB);
  858.     WinDeleteWindow(bitmaps, false);
  859.   }
  860.  
  861.   return 0;
  862. }
  863.